home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Very Best of Atari Inside
/
The Very Best of Atari Inside 1.iso
/
mint
/
mint110s
/
procfs.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-02-15
|
18KB
|
744 lines
/*
Copyright 1991,1992 Eric R. Smith.
Copyright 1992,1993,1994 Atari Corporation.
All rights reserved.
*/
/* PROC pseudo-filesystem routines */
/* basically just to allow 'ls -l X:' to give a list of active processes
* some things to note:
* process names are given as name.XXX, where 'XXX' is the pid of the
* process
* process attributes depend on the run queue as follows:
* RUNNING: 0x00 (normal)
* READY: 0x01 (read-only)
* WAIT: 0x20 (archive bit)
* IOBOUND: 0x21 (archive bit+read-only)
* ZOMBIE: 0x22 (archive+hidden)
* TSR: 0x02 (hidden)
* STOP: 0x24 (archive bit+system)
* the general principle is: inactive processes have the archive bit (0x20)
* set, terminated processes have the hidden bit (0x02) set, stopped processes
* have the system bit (0x04) set, and the read-only bit is used to
* otherwise distinguish states (which is unfortunate, since it would be
* nice if this bit corresponded with file permissions).
*/
#include "mint.h"
static long ARGS_ON_STACK proc_root P_((int drv, fcookie *fc));
static long ARGS_ON_STACK proc_lookup P_((fcookie *dir, const char *name, fcookie *fc));
static long ARGS_ON_STACK proc_getxattr P_((fcookie *fc, XATTR *xattr));
static long ARGS_ON_STACK proc_chattr P_((fcookie *fc, int attrib));
static long ARGS_ON_STACK proc_chown P_((fcookie *fc, int uid, int gid));
static long ARGS_ON_STACK proc_chmode P_((fcookie *fc, unsigned mode));
static long ARGS_ON_STACK proc_rmdir P_((fcookie *dir, const char *name));
static long ARGS_ON_STACK proc_remove P_((fcookie *dir, const char *name));
static long ARGS_ON_STACK proc_getname P_((fcookie *root, fcookie *dir, char *pathname,
int size));
static long ARGS_ON_STACK proc_rename P_((fcookie *olddir, char *oldname,
fcookie *newdir, const char *newname));
static long ARGS_ON_STACK proc_opendir P_((DIR *dirh, int flags));
static long ARGS_ON_STACK proc_readdir P_((DIR *dirh, char *nm, int nmlen, fcookie *));
static long ARGS_ON_STACK proc_rewinddir P_((DIR *dirh));
static long ARGS_ON_STACK proc_closedir P_((DIR *dirh));
static long ARGS_ON_STACK proc_pathconf P_((fcookie *dir, int which));
static long ARGS_ON_STACK proc_dfree P_((fcookie *dir, long *buf));
static DEVDRV * ARGS_ON_STACK proc_getdev P_((fcookie *fc, long *devsp));
static long ARGS_ON_STACK proc_open P_((FILEPTR *f));
static long ARGS_ON_STACK proc_write P_((FILEPTR *f, const char *buf, long bytes));
static long ARGS_ON_STACK proc_read P_((FILEPTR *f, char *buf, long bytes));
static long ARGS_ON_STACK proc_lseek P_((FILEPTR *f, long where, int whence));
static long ARGS_ON_STACK proc_ioctl P_((FILEPTR *f, int mode, void *buf));
static long ARGS_ON_STACK proc_datime P_((FILEPTR *f, short *time, int rwflag));
static long ARGS_ON_STACK proc_close P_((FILEPTR *f, int pid));
/* dummy routines from biosfs.c */
extern long ARGS_ON_STACK null_select P_((FILEPTR *f, long p, int mode));
extern void ARGS_ON_STACK null_unselect P_((FILEPTR *f, long p, int mode));
static PROC * name2proc P_((const char *name));
DEVDRV proc_device = {
proc_open, proc_write, proc_read, proc_lseek, proc_ioctl, proc_datime,
proc_close, null_select, null_unselect
};
FILESYS proc_filesys = {
(FILESYS *)0,
0,
proc_root,
proc_lookup, nocreat, proc_getdev, proc_getxattr,
proc_chattr, proc_chown, proc_chmode,
nomkdir, proc_rmdir, proc_remove, proc_getname, proc_rename,
proc_opendir, proc_readdir, proc_rewinddir, proc_closedir,
proc_pathconf, proc_dfree,
nowritelabel, noreadlabel, nosymlink, noreadlink, nohardlink,
nofscntl, nodskchng
};
long ARGS_ON_STACK
proc_root(drv, fc)
int drv;
fcookie *fc;
{
if (drv == PROCDRV) {
fc->fs = &proc_filesys;
fc->dev = drv;
fc->index = 0L;
return 0;
}
fc->fs = 0;
return EINTRN;
}
static PROC *
name2proc(name)
const char *name;
{
const char *pstr;
char c;
int i;
pstr = name;
while ( (c = *name++) != 0) {
if (c == '.')
pstr = name;
}
if (!isdigit(*pstr) && *pstr != '-')
return 0;
i = (int)atol(pstr);
if (i == -1)
return curproc;
else if (i == -2)
i = curproc->ppid;
return pid2proc(i);
}
static long ARGS_ON_STACK
proc_lookup(dir, name, fc)
fcookie *dir;
const char *name;
fcookie *fc;
{
PROC *p;
if (dir->index != 0) {
DEBUG(("proc_lookup: bad directory"));
return EPTHNF;
}
/* special case: an empty name in a directory means that directory */
/* so does "." */
if (!*name || (name[0] == '.' && name[1] == 0)) {
*fc = *dir;
return 0;
}
/* another special case: ".." could be a mount point */
if (!strcmp(name, "..")) {
*fc = *dir;
return EMOUNT;
}
if (0 == (p = name2proc(name))) {
DEBUG(("proc_lookup: name not found"));
return EFILNF;
} else {
fc->index = (long)p;
fc->fs = &proc_filesys;
fc->dev = PROC_RDEV_BASE | p->pid;
}
return 0;
}
static int p_attr[NUM_QUEUES] = { /* attributes corresponding to queues */
0, /* "RUNNING" */
0x01, /* "READY" */
0x20, /* "WAITING" */
0x21, /* "IOBOUND" */
0x22, /* "ZOMBIE" */
0x02, /* "TSR" */
0x24, /* "STOPPED" */
0x21 /* "SELECT" (same as IOBOUND) */
};
static long ARGS_ON_STACK
proc_getxattr(fc, xattr)
fcookie *fc;
XATTR *xattr;
{
PROC *p;
extern int proctime, procdate; /* see dosmem.c */
xattr->blksize = 1;
if (fc->index == 0) {
/* the root directory */
xattr->index = 0;
xattr->dev = xattr->rdev = PROCDRV;
xattr->nlink = 1;
xattr->uid = xattr->gid = 0;
xattr->size = xattr->nblocks = 0;
xattr->mtime = xattr->atime = xattr->ctime = proctime;
xattr->mdate = xattr->adate = xattr->cdate = procdate;
xattr->mode = S_IFDIR | DEFAULT_DIRMODE;
xattr->attr = FA_DIR;
return 0;
}
p = (PROC *)fc->index;
xattr->index = p->pid;
xattr->dev = xattr->rdev = PROC_RDEV_BASE | p->pid;
xattr->nlink = 1;
xattr->uid = p->ruid; xattr->gid = p->rgid;
xattr->size = xattr->nblocks = memused(p);
xattr->mtime = xattr->ctime = xattr->atime = p->starttime;
xattr->mdate = xattr->cdate = xattr->adate = p->startdate;
xattr->mode = S_IMEM | S_IRUSR | S_IWUSR;
xattr->attr = p_attr[p->wait_q];
return 0;
}
static long ARGS_ON_STACK
proc_chattr(fc, attrib)
fcookie *fc;
int attrib;
{
UNUSED(fc); UNUSED(attrib);
return EACCDN;
}
static long ARGS_ON_STACK
proc_chown(fc, uid, gid)
fcookie *fc;
int uid, gid;
{
UNUSED(fc); UNUSED(uid); UNUSED(gid);
return EINVFN;
}
static long ARGS_ON_STACK
proc_chmode(fc, mode)
fcookie *fc;
unsigned mode;
{
UNUSED(fc); UNUSED(mode);
return EINVFN;
}
static long ARGS_ON_STACK
proc_rmdir(dir, name)
fcookie *dir;
const char *name;
{
UNUSED(dir); UNUSED(name);
return EPTHNF;
}
static long ARGS_ON_STACK
proc_remove(dir, name)
fcookie *dir;
const char *name;
{
PROC *p;
if (dir->index != 0)
return EPTHNF;
p = name2proc(name);
if (!p)
return EFILNF;
/* this check is necessary because the Fdelete code checks for
* write permission on the directory, not on individual
* files
*/
if (curproc->euid && curproc->ruid != p->ruid) {
DEBUG(("proc_remove: wrong user"));
return EACCDN;
}
post_sig(p, SIGTERM);
check_sigs(); /* it might have been us */
return 0;
}
static long ARGS_ON_STACK
proc_getname(root, dir, pathname, size)
fcookie *root, *dir; char *pathname;
int size;
{
PROC *p;
UNUSED(root);
/* BUG: we ought to look at size */
UNUSED(size);
if (dir->index == 0)
*pathname = 0;
else {
p = (PROC *)dir->index;
ksprintf(pathname, "%s.03d", p->name, p->pid);
}
return 0;
}
static long ARGS_ON_STACK
proc_rename(olddir, oldname, newdir, newname)
fcookie *olddir;
char *oldname;
fcookie *newdir;
const char *newname;
{
PROC *p;
int i;
if (olddir->index != 0 || newdir->index != 0)
return EPTHNF;
if ((p = name2proc(oldname)) == 0)
return EFILNF;
oldname = p->name;
for (i = 0; i < PNAMSIZ; i++) {
if (*newname == 0 || *newname == '.') {
*oldname = 0; break;
}
*oldname++ = *newname++;
}
return 0;
}
static long ARGS_ON_STACK
proc_opendir(dirh, flags)
DIR *dirh;
int flags;
{
UNUSED(flags);
dirh->index = 0;
return 0;
}
static long ARGS_ON_STACK
proc_readdir(dirh, name, namelen, fc)
DIR *dirh;
char *name;
int namelen;
fcookie *fc;
{
int i;
int giveindex = (dirh->flags == 0);
PROC *p;
do {
i = dirh->index++;
/* BUG: we shouldn't have the magic number "1000" for maximum proc pid */
if (i >= 1000) {
p = 0;
break;
}
p = pid2proc(i);
} while (!p);
if (!p)
return ENMFIL;
fc->index = (long)p;
fc->fs = &proc_filesys;
fc->dev = PROC_RDEV_BASE | p->pid;
if (giveindex) {
namelen -= (int)sizeof(long);
if (namelen <= 0) return ERANGE;
*((long *)name) = (long)p->pid;
name += sizeof(long);
}
if (namelen < strlen(p->name) + 5)
return ENAMETOOLONG;
ksprintf(name, "%s.%03d", p->name, p->pid);
return 0;
}
static long ARGS_ON_STACK
proc_rewinddir(dirh)
DIR *dirh;
{
dirh->index = 0;
return 0;
}
static long ARGS_ON_STACK
proc_closedir(dirh)
DIR *dirh;
{
UNUSED(dirh);
return 0;
}
static long ARGS_ON_STACK
proc_pathconf(dir, which)
fcookie *dir;
int which;
{
UNUSED(dir);
switch(which) {
case -1:
return DP_MAXREQ;
case DP_IOPEN:
return UNLIMITED; /* no internal limit on open files */
case DP_MAXLINKS:
return 1; /* we don't have hard links */
case DP_PATHMAX:
return PATH_MAX; /* max. path length */
case DP_NAMEMAX:
return PNAMSIZ + 4; /* max. length of individual name */
/* the "+4" is for the pid: ".123" */
case DP_ATOMIC:
return UNLIMITED; /* all writes are atomic */
case DP_TRUNC:
return DP_DOSTRUNC; /* file names are truncated to 8.3 */
case DP_CASE:
return DP_CASEINSENS; /* case preserved, but ignored */
default:
return EINVFN;
}
}
static long ARGS_ON_STACK
proc_dfree(dir, buf)
fcookie *dir;
long *buf;
{
long size;
/* "sector" size is the size of the smallest amount of memory that can be
allocated. see mem.h for the definition of ROUND
*/
long secsiz = ROUND(1);
UNUSED(dir);
size = tot_rsize(core, 0) + tot_rsize(alt, 0);
*buf++ = size/secsiz; /* number of free clusters */
size = tot_rsize(core, 1) + tot_rsize(alt, 1);
*buf++ = size/secsiz; /* total number of clusters */
*buf++ = secsiz; /* sector size (bytes) */
*buf = 1; /* cluster size (in sectors) */
return 0;
}
static DEVDRV * ARGS_ON_STACK
proc_getdev(fc, devsp)
fcookie *fc;
long *devsp;
{
PROC *p;
p = (PROC *)fc->index;
*devsp = (long)p;
return &proc_device;
}
/*
* PROC device driver
*/
/*
* BUG: file locking and the O_SHMODE restrictions are not implemented
* for processes
*/
static long ARGS_ON_STACK
proc_open(f)
FILEPTR *f;
{
UNUSED(f);
return 0;
}
static long ARGS_ON_STACK
proc_write(f, buf, nbytes)
FILEPTR *f; const char *buf; long nbytes;
{
PROC *p = (PROC *)f->devinfo;
char *where;
long bytes_written = 0;
int prot_hold;
where = (char *)f->pos;
TRACE(("proc_write to pid %d: %ld bytes to %lx", p->pid, nbytes, where));
prot_hold = mem_access_for(p, (ulong)where,nbytes);
if (prot_hold == 0) {
DEBUG(("Can't Fwrite that memory: not all the same or not owner."));
return EACCDN;
}
if (prot_hold == 1) {
DEBUG(("Attempt to Fwrite memory crossing a managed boundary"));
return EACCDN;
}
bytes_written = nbytes;
while (nbytes-- > 0) {
*where++ = *buf++;
}
cpush((void *)f->pos, bytes_written); /* flush cached data */
/* MEMPROT: done with temp mapping (only call if temp'ed above) */
if (prot_hold != -1) prot_temp((ulong)f->pos,bytes_written,prot_hold);
f->pos += bytes_written;
return bytes_written;
}
static long ARGS_ON_STACK
proc_read(f, buf, nbytes)
FILEPTR *f; char *buf; long nbytes;
{
PROC *p = (PROC *)f->devinfo;
char *where;
long bytes_read = 0;
int prot_hold;
where = (char *)f->pos;
TRACE(("proc_read from pid %d: %ld bytes from %lx", p->pid, nbytes, where));
prot_hold = mem_access_for(p, (ulong)where,nbytes);
if (prot_hold == 0) {
DEBUG(("Can't Fread that memory: not all the same."));
return EACCDN;
}
if (prot_hold == 1) {
DEBUG(("Attempt to Fread memory crossing a managed boundary"));
return EACCDN;
}
bytes_read = nbytes;
while (nbytes-- > 0) {
*buf++ = *where++;
}
/* MEMPROT: done with temp mapping (only call if temp'ed above) */
if (prot_hold != -1) prot_temp((ulong)f->pos,bytes_read,prot_hold);
f->pos += bytes_read;
return bytes_read;
}
/*
* proc_ioctl: currently, the only IOCTL's available are:
* PPROCADDR: get address of PROC structure's "interesting" bits
* PCTXTSIZE: get the size of the CONTEXT structure
* PBASEADDR: get address of process basepage
* PSETFLAGS: set the memory allocation flags (e.g. to malloc from fastram)
* PGETFLAGS: get the memory allocation flags
* PTRACESFLAGS: set the process tracing flags
* PTRACEGFLAGS: get the process tracing flags
* PTRACEGO: restart the process (T1=0/T1=0)
* PTRACEFLOW: restart the process (T1=0/T0=1)
* PTRACESTEP: restart the process (T1=1/T0=0)
* PTRACE11: restart the process (T1=1/T0=1)
* PLOADINFO: get information about the process name and command line
*/
static long ARGS_ON_STACK
proc_ioctl(f, mode, buf)
FILEPTR *f; int mode; void *buf;
{
PROC *p;
extern long mcpu; /* in main.c */
short sr;
p = (PROC *)f->devinfo;
switch(mode) {
case PPROCADDR:
*((long *)buf) = (long)&p->magic;
return 0;
case PBASEADDR:
if (p == rootproc)
*((long *)buf) = (long)_base;
else
*((long *)buf) = (long)p->base;
return 0;
case PCTXTSIZE:
*((long *)buf) = sizeof(CONTEXT);
return 0;
case PFSTAT:
{
FILEPTR *pf;
int pfd = (*(ushort *)buf);
if (pfd < MIN_HANDLE || pfd >= MAX_OPEN ||
!(pf = p->handle[pfd]))
return EIHNDL;
return (*pf->fc.fs->getxattr)(&pf->fc, (XATTR *)buf);
}
case PSETFLAGS:
{
int newflags = (ushort)(*(long *)buf);
if ((newflags & F_OS_SPECIAL) &&
(!(p->memflags & F_OS_SPECIAL))) {
/* you're making the process OS_SPECIAL */
TRACE(("Fcntl OS_SPECIAL pid %d",p->pid));
p->memflags = newflags;
mem_prot_special(p);
}
/* note: only the low 16 bits are actually used */
p->memflags = *((long *)buf);
return 0;
}
case PGETFLAGS:
*((long *)buf) = p->memflags;
return 0;
case PTRACESFLAGS:
if (p->ptracer == curproc || p->ptracer == 0) {
p->ptraceflags = *(ushort *)buf;
if (p->ptraceflags == 0) {
p->ptracer = 0;
p->ctxt[CURRENT].ptrace = 0;
p->ctxt[SYSCALL].ptrace = 0;
/* if the process is stopped, restart it */
if (p->wait_q == STOP_Q) {
p->sigpending &= ~STOPSIGS;
post_sig(p, SIGCONT);
}
} else if (p == curproc) {
p->ptracer = pid2proc(p->ppid);
} else {
p->ptracer = curproc;
}
} else {
DEBUG(("proc_ioctl: process already being traced"));
return EACCDN;
}
return 0;
case PTRACEGFLAGS:
if (p->ptracer == curproc) {
*(ushort *)buf = p->ptraceflags;
return 0;
} else {
return EACCDN;
}
case PTRACE11:
return EINVFN;
case PTRACEFLOW:
if (mcpu < 20) {
DEBUG(("proc_ioctl: wrong processor"));
return EINVFN;
}
/* fall through */
case PTRACEGO:
case PTRACESTEP:
if (!p->ptracer) {
DEBUG(("proc_ioctl(PTRACE): process not being traced"));
return EACCDN;
}
else if (p->wait_q != STOP_Q) {
DEBUG(("proc_ioctl(PTRACE): process not stopped"));
return EACCDN;
}
else if (p->wait_cond &&
(1L << ((p->wait_cond >> 8) & 0x1f)) & STOPSIGS) {
DEBUG(("proc_ioctl(PTRACE): process stopped by job control"));
return EACCDN;
}
if (buf && *(ushort *)buf >= NSIG) {
DEBUG(("proc_ioctl(PTRACE): illegal signal number"));
return ERANGE;
}
p->ctxt[SYSCALL].sr &= 0x3fff; /* clear both trace bits */
p->ctxt[SYSCALL].sr |= (mode - PTRACEGO) << 14;
p->sigpending = 0;
if (buf && *(ushort *)buf != 0) {
TRACE(("PTRACEGO: sending signal %d to pid %d", *(ushort *)buf, p->pid));
post_sig(p, *(ushort *)buf);
/* another SIGNULL hack... within check_sigs() we watch for a pending
* SIGNULL, if we see this then we allow delivery of a signal to the
* process, rather than telling the parent.
*/
p->sigpending |= 1L;
} else {
TRACE(("PTRACEGO: no signal"));
}
/* wake the process up */
sr = spl7();
rm_q(p->wait_q, p);
add_q(READY_Q, p);
spl(sr);
return 0;
/* jr: PLOADINFO returns information about params passed to Pexec */
case PLOADINFO:
{
struct ploadinfo *pl = buf;
if (!p->fname[0]) return EFILNF;
strncpy (pl->cmdlin, p->cmdlin, 128);
if (strlen (p->fname) <= pl->fnamelen)
strcpy (pl->fname, p->fname);
else
return ENAMETOOLONG;
}
return 0;
case FIONREAD:
case FIONWRITE:
*((long *)buf) = 1L; /* we're always ready for i/o */
return 0;
default:
DEBUG(("procfs: bad Fcntl command"));
}
return EINVFN;
}
static long ARGS_ON_STACK
proc_lseek(f, where, whence)
FILEPTR *f; long where; int whence;
{
switch(whence) {
case 0:
case 2:
f->pos = where;
break;
case 1:
f->pos += where;
break;
default:
return EINVFN;
}
return f->pos;
}
static long ARGS_ON_STACK
proc_datime(f, timeptr, rwflag)
FILEPTR *f;
short *timeptr;
int rwflag;
{
PROC *p;
p = (PROC *)f->devinfo;
if (rwflag) {
return EACCDN;
}
else {
*timeptr++ = p->starttime;
*timeptr = p->startdate;
}
return 0;
}
static long ARGS_ON_STACK
proc_close(f, pid)
FILEPTR *f;
int pid;
{
UNUSED(f); UNUSED(pid);
return 0;
}